'''
NurbsCad
Archivo library utilizado principalmente por todos los modulos de NurbsCad
Autor: Gustavo Enrique Bellino
Contacto: gushbellino@gmail.com
Fecha: Junio de 2009
Descripcion: archivo que dispone de una serie de funciones utilies para todos los modulos
Licencia: GNU Public License version 2
'''

#Importa las librerias necesarias
from lib.euclid import Vector3
import math, ctypes
from OpenGL.raw import GLUT
#MENUFUNC = ctypes.CFUNCTYPE(None, ctypes.c_int) #SEE

#Intenta cargar las librerias de opengl, si no puede cargarlas, informa y sale del programa
try:
  from OpenGL.GLUT import *
  from OpenGL.GL import *
  from OpenGL.GLU import *
except:
  print '''
ERROR: PyOpenGL not installed properly.  
        '''
  sys.exit()



class Library():
    ''' Clase con funciones utiles para los modulos de NurbsCad'''
    def __init__(self):
        ''' No realiza ninguna accion.'''
        return
    
#    def glutCreateMenu(self, menu_func): #SEE
#        """replacement for broken glutCreateMenu"""
#        menu = OpenGL.raw.GLUT.glutCreateMenu(MENUFUNC(menu_func))
#        return menu
    
    def draw_point(self, p, color=(0.0, 0.0, 0.0, 0.5), size = 3):
        ''' p must be a list with three integers.
        @param: p, punto a dibujar de tipo Vector3,
        @param: color, color con la cual dibujar
        @param: size, radio de la esfera'''
        glPushMatrix()
        glPointSize(size)
        glColor4f(color[0], color[1], color[2], color[3])
        glBegin(GL_POINTS)
        glVertex3f(p.x,  p.y,  p.z)
        glEnd()
        glPointSize(1)
        glPopMatrix()

    def draw_rectangule(self, p1, p2, p3, p4, color=(0.0, 0.0, 0.0, 0.5), blendEnable = False):
        ''' Dibuja un rectangulo '''
        glPushMatrix()
        
        #transparency
        if(blendEnable):
            glEnable(GL_BLEND)
            #se desabilita la profundidad
            glDisable(GL_DEPTH_TEST)
        glColor4f(color[0], color[1], color[2], color[3])
        glScalef(0.95, 0.95, 0.95)
        
        #dibuja el cuadrado
        glBegin(GL_QUADS)
        for p in [p1, p2, p3, p4]:
          glVertex3f(p.x, p.y, p.z)
        glEnd();
        glEnable(GL_DEPTH_TEST)
        
        glPopMatrix()
        glEnable(GL_DEPTH_TEST)
        
    #parametros puntoFrom, puntoTo, color
    def draw_line(self, puntoFrom, puntoTo, color=[0.0, 0.0, 0.0, 1], width=1.0):
        ''' Dibuja una linea '''
        ant_width = glGetFloatv(GL_LINE_WIDTH_RANGE)[0]
        if(isinstance(puntoFrom, Vector3) and isinstance(puntoTo, Vector3)):
            glLineWidth(width)
            glBegin(GL_LINES)
            glColor4f(color[0],color[1],color[2],color[3])
            glVertex3d(puntoFrom.x, puntoFrom.y, puntoFrom.z)
            glVertex3d(puntoTo.x, puntoTo.y, puntoTo.z)
            glEnd()
        glLineWidth(ant_width)

    def draw_sphere(self, origen, radius, slices, stacks, color=(0, 0, 0, 0),  blendEnable = False):
        ''' Dibuja una esfera '''
        glPushMatrix()
        if blendEnable:
#            glColor4f(1.0,0.0,0.0,0.0)
#            glBlendFunc(GL_SRC_ALPHA,GL_ONE)
            glEnable(GL_BLEND)
                #se desabilita la profundidad
            glDisable(GL_DEPTH_TEST)        
        glColor4f(color[0], color[1], color[2], color[3])
        glTranslated(origen.x, origen.y, origen.z)
        glutSolidSphere(radius, slices, stacks)
#        if blendEnable:
##            glColor4f(1.0,0.0,0.0,0.0)
##            glBlendFunc(GL_SRC_ALPHA,GL_ONE)
#            glDisable(GL_BLEND)
#                #se desabilita la profundidad
#            glEnable(GL_DEPTH_TEST)        
        glPopMatrix()

    def draw_cone(self, origen, base, height, slices, stacks, color=(0, 0, 0, 0), up = (0, 0, 1)):
        #para el up
        tmp = Vector3(up[0], up[1], up[2])
        ejez = Vector3(0, 0, 1)
        angle = ejez.angle(tmp)
        ejeTmp = (ejez).cross(tmp)
        glPushMatrix()
        glColor4f(color[0], color[1], color[2], color[3])
        glTranslated(origen.x, origen.y, origen.z)
        glRotated(math.degrees(angle), ejeTmp.x, ejeTmp.y, ejeTmp.z)
        glutSolidCone(base, height, slices, stacks)
        glPopMatrix()

    def convertTo2D(self, x, y, z):
        viewport = glGetIntegerv(GL_VIEWPORT)
        modelview = glGetDoublev(GL_MODELVIEW_MATRIX)
        projection = glGetDoublev(GL_PROJECTION_MATRIX)
        winpos = gluProject(x, y, z, modelview, projection, viewport)
        return Vector3(winpos[0], viewport[3] - winpos[1], winpos[2])


    def getCirclePoints(self, radio = 1, quantity = 10):
        half_PI = math.pi / 2
        rango = range(1, quantity)
        lista = []
        #lista de puntos
        lista.append((0, radio))
        lista.append((0, -radio))
        lista.append((radio, 0))
        lista.append((-radio, 0))
        for v in rango:
            ang = ( half_PI * v ) / ( quantity )
            x = radio * math.cos(ang)
            y = radio * math.sin(ang)
            lista.append((x, y))
            lista.append((x, -y))
            lista.append((-x, -y))
            lista.append((-x, y))
        return lista

    def convertTo3D(self, x, y):
        viewport = glGetIntegerv(GL_VIEWPORT)
        modelview = glGetDoublev(GL_MODELVIEW_MATRIX)
        projection = glGetDoublev(GL_PROJECTION_MATRIX)
        winX = x
        winY = y
        winY = viewport[3] - winY
        winZ = glReadPixelsi(winX, winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)
        pos = gluUnProject( winX, winY, winZ, modelview, projection, viewport)
        pos = Vector3(pos[0], pos[1], pos[2])
        return pos

    def isCorrectVector3String(self, valor):
        import re
        exp = '^\((\-)?(\d+)(\.\d+)?(\,)(\-)?(\d+)(\.\d+)?(\,)(\-)?(\d+)(\.\d+)?\)$'
        if(re.search(exp,str(valor))):
            return 'Vector3'+valor
        else:
            return False

    def printVector3(self, valor, digits=100):
        if(valor.x<0.01):
            valor.x = 0.0
        if(valor.y<0.01):
            valor.y = 0.0
        if(valor.z<0.01):
            valor.z = 0.0
        return '('+str(valor.x)[:4] + ',' + str(valor.y)[:4] + ',' + str(valor.z)[:4] + ')'

    def printVector3(self, valor, digits=100):
        return '('+str(round(valor.x*digits)/digits) + ',' + str(round(valor.y*digits)/digits) + ',' + str(round(valor.z*digits)/digits) + ')'

    def drawText( self, value, x,y,  windowHeight, windowWidth, step = 18, color=[0, 0, 0, 0]):
        """Draw the given text at given 2D position in window
        """
        glMatrixMode(GL_PROJECTION);
        matrix = glGetDouble( GL_PROJECTION_MATRIX )
        
        glLoadIdentity();
        glOrtho(0.0, windowWidth, 0.0, windowHeight, -1.0, 1.0)
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glColor4f(color[0], color[1], color[2], color[3])
        glLoadIdentity();
        glRasterPos2i(x, y);
        lines = 0
        for character in value:
            if character == '\n':
                glRasterPos2i(x, y-(lines*18))
            else:
                glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, ord(character));
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glLoadMatrixd( matrix ) # should have un-decorated alias for this...
        
        glMatrixMode(GL_MODELVIEW);

def main():
    lib = library()
    lista = lib.getCirclePoints()
    #print lista
    return 0
if __name__ == '__main__':
    main()
